package controller;

import java.util.List;
import java.util.Observer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

import serverMessage.ServerMessage;

import database.DbFile;
import database.DbFolder;
import database.User;
import model.AddFileRequest;
import model.AddFolderRequest;
import model.AddUserRequest;
import model.DbAdapter;
import model.DeleteFileRequest;
import model.DeleteFolderRequest;
import model.ModifyFileRequest;
import model.Request;
import model.RequestsManager;
import model.UsersMessages;


/**
 * class ExecutorsManager - singleton. contain several of executors classes - 
 * each of them pass some request from View part to Model part in MVC model.
 */
public class ExecutorsManager {
	
	//singleton
	private static ExecutorsManager managerSingleton = new ExecutorsManager();
	
	/*save queue of requests - each executor create suitable request (=job) and
	add it to the requests manager*/
	private RequestsManager requestsManager;
	
	//the executors
	AddUserExecutor addUserExecutor;
	AddFileExecutor addFileExecutor;
	DeleteFileExecutor deleteFileExecutor;
	ModifyFileExecutor modifyFileExecutor;
	AddFolderExecutor addFolderExecutor;
	AddSharedFolderExecutor addSharedFolderExecutor;
	DeleteFolderExecutor deleteFolderExecutor;
	UserDropBoxFoldersExecutor userDropBoxFoldersExecutor;
	UserDropBoxFilesExecutor userDropBoxFilesExecutor;
	FilesInUserFolderNameExecutor filesInUserFolderNameExecutor;
	AddObserverUsersStatusExecutor addObserverUsersStatusExecutor;
	GetUserExecutor getUserExecutor;
	
	//private ctor
	private ExecutorsManager() 
	{	
		requestsManager = RequestsManager.getInstance();
		
		//the commands executors
		addUserExecutor = new AddUserExecutor();
		addFileExecutor = new AddFileExecutor();
		deleteFileExecutor = new DeleteFileExecutor();
		modifyFileExecutor = new ModifyFileExecutor();
		addFolderExecutor = new AddFolderExecutor();
		addSharedFolderExecutor = new AddSharedFolderExecutor();
		deleteFolderExecutor = new DeleteFolderExecutor();
		userDropBoxFoldersExecutor = new UserDropBoxFoldersExecutor();
		userDropBoxFilesExecutor = new UserDropBoxFilesExecutor();
		filesInUserFolderNameExecutor = new FilesInUserFolderNameExecutor();
		addObserverUsersStatusExecutor = new AddObserverUsersStatusExecutor();
		getUserExecutor = new GetUserExecutor();
	}
	
	/**
	 * @return an instance of ExecutorsManager class (singleton)
	 */
	public static ExecutorsManager getInstance()
	{		
		return managerSingleton;	
	}

	/***
	 * class AddUserExecutor - execute an add user request. 
	 */
	public class AddUserExecutor {
		
		//private ctor
		private AddUserExecutor() {}
		
		/**
		 * @param userName - user name to add
		 * @param password - the password of the user
		 * @return 1 - if succeed. 0 - if failed. 
		 */
		public int addRequest(String userName, String password)
		{
			Request req = new AddUserRequest(userName,password);
			return requestsManager.addRequest(req);
		}	
	}
	
	
	/***
	 * class AddFileExecutor - execute an add file request. 
	 */
	public class AddFileExecutor {
		
		//private ctor
		private AddFileExecutor() {}
		
		/***
		 * add user file
		 * @param userID - the user that the file refer to
		 * @param fileName - the name of the file
		 * @param filePath - the path of the file
		 * @param byteFile - the content of the file
		 * @param checksum - checksum of the file (hash on the content)
		 * @param isMyDropBox - 1 if the file is directly in the dropbox folder, else 0 .
		 * @return  1 - if succeed. 0 - if failed. 
		 */
		public int addRequest(String userID,String fileName,String filePath,byte[] byteFile, long checksum, boolean isMyDropBox, boolean isWebUpload)
		{
			Request req = new AddFileRequest(userID, fileName, filePath, byteFile, checksum, isMyDropBox, isWebUpload);
			return requestsManager.addRequest(req);
		}	
	}
	
	
	/***
	 * class DeleteFileExecutor - execute a delete file request. 
	 */
	public class DeleteFileExecutor {
		
		//private ctor
		private DeleteFileExecutor() {}
		
		/**
		 * delete user file
		 * @param userID - the user that the file refer to
		 * @param fileName - the name of the file
		 * @param filePath - the path of the file
		 * @param isMyDropBox - 1 if the file is directly in the dropbox folder, else 0 .
		 * @return  1 - if succeed. 0 - if failed. 
		 */
		public int addRequest(String userID,String fileName,String filePath, boolean isMyDropBox)
		{
			Request req = new DeleteFileRequest(userID, fileName, filePath, isMyDropBox);
			return requestsManager.addRequest(req);
		}	
	}
	
	
	/***
	 * class ModifyFileExecutor - execute a modify file request. 
	 */
	public class ModifyFileExecutor {
		
		//private ctor
		private ModifyFileExecutor() {}
		
		/**
		 * update a modification of file
		 * @param userID - the user that the file refer to
		 * @param fileName - the name of the file
		 * @param filePath - the path of the file
		 * @param byteFile - the content of the file
		 * @param checksum - checksum of the file (hash on the content)
		 * @param isMyDropBox - 1 if the file is directly in the dropbox folder, else 0 .
		 * @return  1 - if succeed. 0 - if failed. 
		 */
		public int addRequest(String userID,String fileName,String filePath,byte[] byteFile, long checksum, boolean isMyDropBox)
		{
			Request req = new ModifyFileRequest(userID, fileName, filePath, byteFile, checksum, isMyDropBox);
			return requestsManager.addRequest(req);
		}	
	}
	
	
	/***
	 * class AddFolderExecutor - execute an add folder request.
	 */
	public class AddFolderExecutor {
		
		//private ctor
		private AddFolderExecutor() {}
		
		/**
		 * add user folder
		 * @param userID - the user that the folder refer to
		 * @param folderName - the name of the folder
		 * @return  1 - if succeed. 0 - if failed. 
		 */
		public int addRequest(String userID,String folderName)
		{
			Request req = new AddFolderRequest(userID, folderName);
			return requestsManager.addRequest(req);
		}	
	}
	
	
	/***
	 * class AddSharedFolderExecutor - execute an add shared folder request.
	 */
	public class AddSharedFolderExecutor {
		
		//private ctor
		private AddSharedFolderExecutor() {}
		
		/**
		 * add shared folder
		 * @param fromUserID - the user that want to shared the folder
		 * @param folderName - the name the folder
		 * @param toUserID - the user that 'fromUserID' shared with 
		 * @return  1 - if succeed. 0 - if failed. 
		 */
		public Integer sharedFolder(String fromUserID,String folderName, String toUserID)
		{
			return DbAdapter.getInstance().shareFolder(fromUserID, folderName, toUserID);
		}	
	}
	
	/***
	 * class DeleteFolderExecutor - execute a delete folder request.
	 */
	public class DeleteFolderExecutor {
		
		//private ctor
		private DeleteFolderExecutor() {}
		
		/**
		 * delete user folder
		 * @param userID - the user that the folder refer to
		 * @param folderName - the name the folder
		 * @return 1
		 */
		public int addRequest(String userID,String folderName)
		{
			System.out.println("delete folder executor");
			Request req = new DeleteFolderRequest(userID, folderName);
			return requestsManager.addRequest(req);
		}	
	}
	
	/***
	 * class UserDropBoxFoldersExecutor - execute folders in a user dropbox request.
	 */
	public class UserDropBoxFoldersExecutor {
		
		//private ctor
		private UserDropBoxFoldersExecutor() {}
		
		/***
		 * @param userID - a user name
		 * @return a list of the folders in the user dropbox
		 */
		public List<DbFolder> getUserDropBoxFolders(String userID)
		{			
			return DbAdapter.getInstance().getUserDropboxFolders(userID);
		}	
	}
	
	/**
	 * class UserDropBoxFilesExecutor - execute files that directly under the user dropbox request.
	 */
	public class UserDropBoxFilesExecutor {
		
		//private ctor
		private UserDropBoxFilesExecutor() {}
		
		/**
		 * @param userID - a user name
		 * @return the files that directly under the user dropbox root
		 */
		public List<DbFile> getUserDropBoxFiles(String userID)
		{
			return DbAdapter.getInstance().getUserDropboxFiles(userID);
		}	
	}
	
	/**
	 * class FilesInUserFolderNameExecutor - execute files in a user folder request
	 */
	public class FilesInUserFolderNameExecutor {
		
		//private ctor
		private FilesInUserFolderNameExecutor() {}
		
		/***
		 * @param userID - a user name
		 * @param folderName - a user folder name
		 * @return a list of files that under the user folder
		 */
		public List<DbFile> getFilesInUserFolderName(String userID, String folderName)
		{
			return DbAdapter.getInstance().getFilesInUserFolderName(userID, folderName);
		}	
	}
	
	/**
	 * class GetUserExecutor - execute get user request
	 */
	public class GetUserExecutor {
		
		//private ctor
		private GetUserExecutor() {}
		
		/**
		 * @param userID - a user name
		 * @return a User instance of that user 
		 */
		public User getUser(String userID)
		{			
			return DbAdapter.getInstance().getUser(userID);
		}	
	}
	
	
	/**
	 * class AddObserverUsersStatusExecutor - execute add observer to UsersStatus request
	 */
	public class AddObserverUsersStatusExecutor {
		
		//private ctor
		private AddObserverUsersStatusExecutor() {}
		
		/**
		 * register this observer for changes in users status hash map -
		 * tell when this hash map change, mean when a new message arrived for passing it
		 * to a user
		 * @param observer - observer that wand to register to changes in user status (a queue of messages to a user)
		 * @return a hash map of messages to users (when get update mean the hash map was changed)
		 */
		public ConcurrentHashMap<String, ConcurrentLinkedQueue<ServerMessage>> addObserverUsersStatus(Observer observer)
		{
			return UsersMessages.getInstance().addObserverOnUsersStatus(observer);
		}	
	}
	

	//getters//

	/**
	 * @return an instance of AddUserExecutor
	 */
	public AddUserExecutor getAddUserExecutor() {
		return addUserExecutor;
	}
	
	/**
	 * @return an instance of AddFileExecutor
	 */
	public AddFileExecutor getAddFileExecutor() {
		return addFileExecutor;
	}
	
	/**
	 * @return an instance of DeleteFileExecutor
	 */
	public DeleteFileExecutor getDeleteFileExecutor() {
		return deleteFileExecutor;
	}
	
	/**
	 * @return an instance of ModifyFileExecutor
	 */
	public ModifyFileExecutor getModifyFileExecutor() {
		return modifyFileExecutor;
	}

	/**
	 * @return an instance of AddFolderExecutor
	 */
	public AddFolderExecutor getAddFolderExecutor() {
		return addFolderExecutor;
	}
	
	/**
	 * @return an instance of DeleteFolderExecutor
	 */
	public DeleteFolderExecutor getDeleteFolderExecutor() {
		return deleteFolderExecutor;
	}

	/**
	 * @return an instance of UserDropBoxFoldersExecutor
	 */
	public UserDropBoxFoldersExecutor getUserDropBoxFoldersExecutor() {
		return userDropBoxFoldersExecutor;
	}

	/**
	 * @return an instance of GetUserExecutor
	 */
	public GetUserExecutor getGetUserExecutor() {
		return getUserExecutor;
	}

	/**
	 * @return an instance of UserDropBoxFilesExecutor
	 */
	public UserDropBoxFilesExecutor getUserDropBoxFilesExecutor() {
		return userDropBoxFilesExecutor;
	}

	/**
	 * @return an instance of FilesInUserFolderNameExecutor
	 */
	public FilesInUserFolderNameExecutor getFilesInUserFolderNameExecutor() {
		return filesInUserFolderNameExecutor;
	}

	/**
	 * @return an instance of AddSharedFolderExecutor
	 */
	public AddSharedFolderExecutor getAddSharedFolderExecutor() {
		return addSharedFolderExecutor;
	}

	/**
	 * @return an instance of AddObserverUsersStatusExecutor
	 */
	public AddObserverUsersStatusExecutor getAddObserverUsersStatusExecutor() {
		return addObserverUsersStatusExecutor;
	}




}
